﻿using System;
using System.Threading;

namespace EasyConveyor
{
	/// <summary>
	/// A base class representing an implementation of the dispose pattern with thread-safety.
	/// </summary>
	public abstract class ThreadSafeDisposePatternBase : IDisposable
	{
		private int _isDisposed;

		/// <summary>
		/// Destructor.
		/// </summary>
		~ThreadSafeDisposePatternBase()
		{
			Dispose(false);
		}

		private void Dispose(bool disposing)
		{
			if (Interlocked.Exchange(ref _isDisposed, 1) != 0) return;

			if (disposing)
			{
				DisposeManagedResources();
			}
			DisposeUnmanagedResources();
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		/// <remarks>This method should not be overridden in a derived class. Rather, the <see cref="ThreadSafeDisposePatternBase.DisposeUnmanagedResources" /> should be overridden for cleaning up class resources.</remarks>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Gets a <see cref="bool"/> indicating whether this instance has been disposed or not.
		/// </summary>
		protected bool IsDisposed
		{
			get { return _isDisposed != 0; }
		}

		/// <summary>
		/// Asserts that this instance has not been disposed; if it has, throws an <see cref="ObjectDisposedException"/>.
		/// </summary>
		protected void CheckDisposed()
		{
			if (IsDisposed)
				throw new ObjectDisposedException(GetType().Name);
		}

		/// <summary>
		/// When overridden in a derived class, used to clean up any managed resources.
		/// </summary>
		protected virtual void DisposeManagedResources()
		{
		}

		/// <summary>
		/// When overridden in a derived class, used to clean up any unmanaged resources.
		/// </summary>
		protected abstract void DisposeUnmanagedResources();
	}
}
